package encrypting

import (
	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"
	"encoding/base64"
	"fmt"
	"golang.org/x/crypto/scrypt"
	"io"
)

/*
单向哈希有两个特性：

1）同一个密码进行单向哈希，得到的总是唯一确定的摘要。
2）计算速度快。随着技术进步，一秒钟能够完成数十亿次单向哈希计算。
*/

type SingleDirectEncrypt struct {
}

func (_ *SingleDirectEncrypt) EncryptDemo() {
	h := md5.New()
	io.WriteString(h, "how many md5 encrypt for password")
	buf := h.Sum(nil)
	fmt.Printf("md5:\n% x\n%x\n%X\n", buf, buf, buf)

	h = sha1.New()
	io.WriteString(h, "how many md5 encrypt for password")
	buf = h.Sum(nil)
	fmt.Printf("sha1:\n% x\n%x\n%X\n", buf, buf, buf)

	h = sha256.New()
	io.WriteString(h, "how many md5 encrypt for password")
	buf = h.Sum(nil)
	fmt.Printf("sha256:\n% x\n%x\n%X\n", buf, buf, buf)

	h = sha512.New()
	io.WriteString(h, "how many md5 encrypt for password")
	buf = h.Sum(nil)
	fmt.Printf("sha512:\n% x\n%x\n%X\n", buf, buf, buf)
}

// 加盐加密
func (_ *SingleDirectEncrypt) SaltEncrypt(username string, pwd string) string {
	h := md5.New()
	io.WriteString(h, pwd)

	pwdmd5 := fmt.Sprintf("%x", h.Sum(nil))

	// 指定两个salt: salt1,salt2
	salt1 := "@#$%2020"
	salt2 := "^&*(2020)"

	// salt1+username+salt2+md5拼接
	io.WriteString(h, salt1)
	io.WriteString(h, username)
	io.WriteString(h, salt2)
	io.WriteString(h, pwdmd5)

	result := fmt.Sprintf("%x", h.Sum(nil))
	return result
}

/*
增加计算强度:scrypt
目前Go语言里面支持的库 https://github.com/golang/crypto/tree/master/scrypt
通过以下的方法可以获取唯一的相应的密码值，这是目前为止最难破解的。
*/
func (_ *SingleDirectEncrypt) ScryptTest(pwd, salt string) string {
	// salt最好是8 bytes
	dk, _ := scrypt.Key([]byte(pwd), []byte(salt), 16384, 8, 1, 32)
	return base64.StdEncoding.EncodeToString(dk)
}

func Test() {
	sde := SingleDirectEncrypt{}
	sde.EncryptDemo()
	fmt.Println("salt encrypt(dralee,123456):", sde.SaltEncrypt("dralee", "123456"))
	fmt.Println("scrypt(dralee,123456):", sde.ScryptTest("123456", "2020#&12.17"))
}
